package com.decent.common.aspect;

import com.decent.common.util.http.GetIpUtil;
import com.decent.common.util.jackson.ReturnCheckJacksonUtil;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Parameter;
import java.util.List;

/**
 * 日志切面
 *
 * @author wangyan
 **/
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Resource
    private HttpServletRequest request;

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
            " || @annotation(org.springframework.web.bind.annotation.GetMapping) " +
            "||  @annotation(org.springframework.web.bind.annotation.PostMapping)")
    private void controllerAspect() {
    }

    /**
     * 日志切面
     *
     * @param pjp 连接点
     * @return java.lang.Object
     */
    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        // 拦截的方法参数
        Object[] args = pjp.getArgs();
        // 拦截的类型
        Signature sig = pjp.getSignature();
        MethodSignature msig;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Parameter[] parameters = msig.getMethod().getParameters();
        String logFormat = "LogAspect-RequestMethod[%s => %s],IP[%s],RequestURL[%s],Params[%s],StartTime[%d]EndTime[%d]Duration[%d],Response[%s]";
        StringBuilder params = new StringBuilder(32);
        int i = 0;
        for (Parameter parameter : parameters) {
            params.append(parameter.getName()).append(" ");
            params.append(args[i++]).append(" ");
        }
        long startTime = System.currentTimeMillis();
        Object object = pjp.proceed();
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        if (object instanceof PageInfo || object instanceof List) {
            log.info(String.format(logFormat, target.getClass().getSimpleName(), methodName, GetIpUtil.getIp(), request.getRequestURL(), params, startTime, endTime, duration, ""));
            return object;
        }
        log.info(String.format(logFormat, target.getClass().getSimpleName(), methodName, GetIpUtil.getIp(), request.getRequestURL(), params, startTime, endTime, duration, ReturnCheckJacksonUtil.beanToJson(object)));
        return object;
    }
}
